﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using ManaMaple.Kit.Exceptions;
using ManaMaple.Kit.Models;
using Microsoft.Extensions.Logging;
using ManaMaple.Kit.Enum;
using FreeSql.Internal;

namespace ManaMaple.Core.Middlewares
{
    /// <summary>
    /// 自定义异常中间件
    /// </summary>
    public class CustomerExceptionMiddleware
    {
        /// <summary>
        /// 委托
        /// </summary>
        private readonly RequestDelegate _next;
        private readonly ILogger<CustomerExceptionMiddleware> _logger;

        public CustomerExceptionMiddleware(RequestDelegate next, ILogger<CustomerExceptionMiddleware> logger)
        {
            _next = next;
            _logger = logger;
        }

        public async Task Invoke(HttpContext context)
        {
            try
            {
                await _next(context);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Application error: {Message}", ex.Message);
                await HandleExceptionAsync(context, ex);
            }
        }

        private async Task HandleExceptionAsync(HttpContext context, Exception exception)
        {
            context.Response.ContentType = "application/json";
            context.Response.StatusCode = (int)HttpStatusCode.OK; // 总是返回200，通过自定义状态码区分错误

            ApiResponse response;

            switch (exception)
            {
                case CustomHttpException httpException:
                    _logger.LogWarning("HTTP异常: {Code} - {Message}", 
                        httpException.ErrorCode, httpException.ErrorMessage);
                    var errCode = (ResultCode)Convert.ToInt32(httpException.ErrorCode ?? "400");
                    response = ApiResponse.Fail(
                       errCode, 
                        httpException.ErrorMessage ?? "请求处理异常");
                    break;

                case UnauthorizedAccessException _:
                    _logger.LogWarning("未授权访问异常: {Message}", exception.Message);
                    response = ApiResponse.Fail(ResultCode.LoginExpired, "未授权的访问");
                    break;

                case InvalidOperationException _:
                    _logger.LogWarning("无效操作异常: {Message}", exception.Message);
                    response = ApiResponse.Fail($"无效的操作: {exception.Message}");
                    break;

                case ArgumentException _:
                    _logger.LogWarning("参数异常: {Message}", exception.Message);
                    response = ApiResponse.Fail($"参数错误: {exception.Message}");
                    break;
                case DbUpdateVersionException _:
                    _logger.LogWarning("数据已经更新,请刷新后重试: {Message}", exception.Message);
                    response = ApiResponse.Fail($"当前数据不是最新数据,请刷新后重试");
                    break;
                    
                default:
                    // 处理其他类型的异常，例如数据库异常、服务不可用等
                    _logger.LogError(exception, "未处理的异常类型: {Type}", exception.GetType().Name);
                    
                    // 生产环境中不返回详细错误信息，避免信息泄露
                    var isDevelopment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development";
                    var errorMessage = isDevelopment ? exception.ToString() : "服务器内部错误，请稍后再试";
                    
                    response = ApiResponse.Fail(errorMessage);
                    break;
            }

            // 添加异常追踪信息，仅在开发环境中显示
            if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development")
            {
                response.Data = new 
                {
                    StackTrace = exception.StackTrace,
                    Source = exception.Source,
                    TypeName = exception.GetType().Name
                };
            }

            await context.Response.WriteAsync(JsonSerializer.Serialize(response, new JsonSerializerOptions
            {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                WriteIndented = true
            }));
        }
    }
}
